#!/bin/sh -ef
#
# Copyright (C) 2003-2019  Dmitry V. Levin <ldv@altlinux.org>
# Copyright (C) 2006  Alexey Gladkov <legion@altlinux.org>
# Copyright (C) 2007  Kirill A. Shutemov <kas@altlinux.org>
# 
# The hsh utility for the hasher project
#
# SPDX-License-Identifier: GPL-2.0-or-later
#

. hsh-sh-functions

show_help()
{
	cat <<EOF
hsh - build package using hasher utilities.

Usage: $PROG [options] [<path-to-workdir>] <package>...

<path-to-workdir> must be valid writable directory.

Options:
  --apt-config=FILE                 path to custom apt.conf file;
  --apt-prefix=DIR                  path to apt directory prefix (e.g. /usr);
  --build-args=ARGS                 a deprecated synonym for --rpmbuild-args;
  --build-srpm-only                 do not build binary packages, produce src.rpm only;
  --cleanup-only                    do not build at all, just cleanup workdir;
  --eager-cleanup                   cleanup build environment after each
                                    successful build;
  --lazy-cleanup                    cleanup build environment before each
                                    new build;
  --excludedocs                     do not install documentation files;
  --hasher-priv-dir=DIR             alternative hasher-priv directory;
  --initroot-only                   do not build, stop after initroot stage;
  --printenv                        print configuration environment variables;
  --install-langs=LIST              colon-separated list of languages to install;
  --mountpoints=LIST                comma-separated list of known mount points;
  --cache-compress=FILE             alternative cache compress executable;
  --cache-dir=DIR                   alternative cache directory;
  --no-cache                        do not use initroot cache;
  --no-contents-indices             do not use content indices;
  --no-repackage-source             do not repackage source along with binaries;
  --no-sisyphus-check-in[=LIST]     do not run sisyphus_check input tests
                                    [specified in comma-separated LIST];
  --no-sisyphus-check[=LIST]        do not run sisyphus_check tests
                                    [specified in comma-separated LIST];
  --no-sisyphus-check-out[=LIST]    do not run sisyphus_check output tests
                                    [specified in comma-separated LIST];
  --nprocs=NUMBER                   number of CPUs to use;
  --number=NUMBER                   subconfig identifier;
  --packager=EMAIL                  override default RPM packager tag;
  --pkg-build-list=LIST             override default build package file list;
  --pkg-init-list=LIST              override default initial package file list;
  --query-repackage                 repackage the source before query
                                    for requirements (default);
  --no-query-repackage              query original source package
                                    for requirements;
  --query-req-prog=FILE             program to run to query for requirements
                                    instead of autogenerated script;
  --rebuild-prog=FILE               program to run for rebuild instead of
                                    autogenerated script;
  --repackage-source                repackage source along with binaries;
  --repo=DIR                        repository directory;
  --repo-bin=DIR                    binary packages destination directory,
                                    overriding --repo option for binary packages;
  --repo-src=DIR                    source packages destination directory,
                                    overriding --repo option for source packages;
  --rpmbuild-args=ARGS              extra arguments for rpmbuild;
  --save-fakeroot                   save fakeroot state;
  --target=ARCH                     target architecture;
  --wait-lock                       wait for workdir and hasher-priv locks;
  --no-wait-lock                    do not wait for workdir and hasher-priv locks;
  --without-stuff                   do not use built packages;
  --with-stuff                      allow use of built packages;
  --with-qemu=ARCH                  copy qemu executable into the chroot .host directory;
  -q, --quiet                       try to be more quiet;
  -v, --verbose                     print a message for each action;
  -V, --version                     print program version and exit;
  -h, --help                        show this text and exit.
    
Report bugs to http://bugs.altlinux.ru/

EOF
	exit
}

TEMP=`getopt -n $PROG -o $getopt_common_opts -l apt-config:,apt-prefix:,build-args:,build-srpm-only,cache-compress:,cache-dir:,cleanup-only,contents-index-all:,contents-index-bin:,eager-cleanup,excludedocs,hasher-priv-dir:,initroot-only,install-langs:,lazy-cleanup,mountpoints:,no-cache,no-contents-indices,no-repackage-source,no-sisyphus-check::,no-sisyphus-check-in::,no-sisyphus-check-out::,no-stuff,nprocs:,number:,packager:,pkg-build-list:,pkg-init-list:,query-repackage,query-req-prog:,printenv,rebuild-prog:,repackage-source,repo:,repo-bin:,repo-src:,rpmbuild-args:,save-fakeroot,target:,wait-lock,no-wait-lock,without-stuff,with-stuff,with-qemu:,$getopt_common_longopts -- "$@"` ||
	show_usage
eval set -- "$TEMP"

cleanup_only=
initroot_only=
printenv_only=
build_srpm_only=
query_repackage_option=
while :; do
	case "$1" in
		--apt-config)
			apt_config="$(opt_check_read "$1" "$2")"
			shift
			;;
		--apt-prefix)
			apt_prefix="$(opt_check_dir "$1" "$2")"
			shift
			;;
		--build-srpm-only) build_srpm_only="$1"
			;;
		--cache-compress) shift; cache_compress="$1"
			;;
		--cache-dir) shift; cache_dir="$1"
			;;
		--cleanup-only) cleanup_only=1
			;;
		--eager-cleanup) lazy_cleanup=
			;;
		--excludedocs) exclude_docs=--excludedocs
			;;
		--hasher-priv-dir)
			hasher_priv_dir="$(opt_check_dir "$1" "$2")"
			shift
			;;
		--initroot-only) initroot_only=1
			;;
		--install-langs) shift; install_langs="$1"
			;;
		--lazy-cleanup) lazy_cleanup=1
			;;
		--mountpoints) shift; known_mountpoints="$1"
			;;
		--no-cache) no_cache=1
			;;
		--no-contents-indices) no_contents_indices=1
			;;
		--no-repackage-source|--repackage-source) repackage_source="$1"
			;;
		--no-sisyphus-check) shift
			[ -n "$1" ] && no_sisyphus_check="$1" || no_sisyphus_check=all
			;;
		--no-sisyphus-check-in) shift
			[ -n "$1" ] && no_sisyphus_check_in="$1" || no_sisyphus_check_in=all
			;;
		--no-sisyphus-check-out) shift
			[ -n "$1" ] && no_sisyphus_check_out="$1" || no_sisyphus_check_out=all
			;;
		--nprocs)
			nprocs="$(opt_check_number "$1" "$2")"
			shift
			;;
		--number)
			if [ -z "${2##/*}" ]; then
				[ -d "$2" ] ||
					fatal "$1: $2: Directory not available."
				number="$2"
			else
				number="$(opt_check_number_ge_0 "$1" "$2")"
			fi
			shift
			;;
		--packager) shift; packager="$1"
			;;
		--pkg-build-list) shift; build_list="$1 "
			;;
		--pkg-init-list) shift; init_list="$1 "
			;;
		--printenv) printenv_only=1
			;;
		--query-repackage)
			query_repackage=1
			query_repackage_option="$1"
			;;
		--no-query-repackage)
			query_repackage=
			query_repackage_option="$1"
			;;
		--query-req-prog)
			prog_query_req="$(opt_check_read "$1" "$2")"
			shift
			;;
		--rebuild-prog)
			prog_rebuild="$(opt_check_read "$1" "$2")"
			shift
			;;
		--repo) shift; repo="$1"
			;;
		--repo-bin) shift; repo_bin="$1"
			;;
		--repo-src) shift; repo_src="$1"
			;;
		--rpmbuild-args|--build-args) shift; rpmargs="$1"
			;;
		--save-fakeroot) save_fakeroot=1
			;;
		--target) shift; target="$1"
			[ -z "${target##[A-Za-z]*}" ] ||
				fatal "--target: $target: invalid architecture."
			;;
		--wait-lock) lock_nowait=
			;;
		--no-wait-lock) lock_nowait=1
			;;
		--without-stuff|--no-stuff) no_stuff=1
			;;
		--with-stuff) no_stuff=
			;;
		--with-qemu)
			qemu_arch="$2"
			shift
			;;
		--contents-index-*)
			message "Warning: obsolete option $1 ignored."
			shift
			;;
		--) shift; break
			;;
		*) parse_common_option "$1"
			;;
	esac
	shift
done

[ "$repackage_source" = '--no-repackage-source' ] ||
	repackage_source='--repackage-source'

case "${initroot_only:+1}${cleanup_only:+1}${printenv_only:+1}" in
	11*) show_usage '--initroot-only, --cleanup-only and --printenv are mutually exclusive options.' ;;
esac

if [ -n "$prog_query_req" ] && [ -n "$query_repackage_option" ]; then
	show_usage "--query-req-prog and $query_repackage_option are mutually exclusive options."
fi

if [ -z "$initroot_only" -a -z "$cleanup_only" -a -z "$printenv_only" ]; then
	if [ -z "$workdir" ]; then
		# At least two arguments.
		[ "$#" -ge 2 ] || show_usage 'Insufficient arguments.'
	else
		# At least one argument.
		[ "$#" -ge 1 ] || show_usage 'Insufficient arguments.'
	fi

	[ -e "$1" ] || fatal "$1: no such file or directory."

	if [ -z "$workdir" -o -d "${1:-}" ]; then
		set_workdir "${1:-}"
		shift
	else
		set_workdir
	fi

	# At least one argument.
	[ "$#" -ge 1 ] || show_usage 'Insufficient arguments.'
else
	if [ -z "$workdir" ]; then
		# Exactly one argument.
		[ "$#" -ge 1 ] || show_usage 'Insufficient arguments.'
		[ "$#" -le 1 ] || show_usage 'Too many arguments.'
	else
		# At most one argument.
		[ "$#" -le 1 ] || show_usage 'Too many arguments.'
	fi

	if [ "$#" -ge 1 ]; then
		set_workdir "$1"
		shift
	else
		set_workdir
	fi
fi

for f in "$@"; do
	[ -z "${f##/*}" ] || f="$saved_cwd/$f"
	[ -e "$f" ] ||
		fatal "$f: file not found."
	[ -f "$f" ] ||
		fatal "$f: not a regular file."
	[ -r "$f" ] ||
		fatal "$f: cannot access source."
	[ -s "$f" ] ||
		fatal "$f: empty source file."
done

[ -z "$nprocs" ] ||
	opt_check_number nprocs "$nprocs" > /dev/null

cleanup_workdir()
{
	if [ -d chroot ]; then
		deduce_lock_hasher_priv
		hsh-rmchroot --no-lock "$workdir" \
			${hasher_priv_dir:+--hasher-priv-dir="$hasher_priv_dir"} \
			${quiet:+$quiet} \
			${verbose:+$verbose} \
			${number:+--number=$number} \
			&&
			verbose 'Removed chroot.' ||
			fatal 'Failed to remove chroot.'
	fi
	if [ -d aptbox ]; then
		rm -rf aptbox &&
			verbose 'Removed aptbox.' ||
			fatal 'Failed to remove aptbox.'
	fi
	if [ -d cache ]; then
		rm -rf cache &&
			verbose 'Removed cache.' ||
			fatal 'Failed to remove cache.'
	fi
	if [ -d repo ]; then
		rm -rf repo &&
			verbose 'Removed repo.' ||
			fatal 'Failed to remove repo.'
	fi
}

handle_package()
{
	local f="$1" && shift ||:
	[ -z "${f##/*}" ] || f="$saved_cwd/$f"

	rm -rf aptbox
	if [ -d chroot ]; then
		deduce_lock_hasher_priv
		hsh-rmchroot --no-lock "$workdir" \
		${hasher_priv_dir:+--hasher-priv-dir="$hasher_priv_dir"} \
		${quiet:+$quiet} \
		${verbose:+$verbose} \
		${number:+--number=$number} \
		#
	else
		if [ -n "$number" -a -z "${number##/*}" ]; then
			deduce_lock_hasher_priv "$number"
		else
			allocate_lock_hasher_priv
		fi
	fi

	mkaptbox --no-lock "$workdir" \
		${target:+--target="$target"} \
		${repo:+--repo="$repo"} \
		${repo_bin:+--repo-bin="$repo_bin"} \
		${repo_src:+--repo-src="$repo_src"} \
		${apt_config:+--apt-config="$apt_config"} \
		${apt_prefix:+--apt-prefix="$apt_prefix"} \
		${quiet:+$quiet} \
		${verbose:+$verbose} \
		${no_stuff:+--no-stuff} \
		#
	hsh-mkchroot --no-lock "$workdir" \
		${hasher_priv_dir:+--hasher-priv-dir="$hasher_priv_dir"} \
		${quiet:+$quiet} \
		${verbose:+$verbose} \
		${number:+--number=$number} \
		${qemu_arch:+--with-qemu=$qemu_arch} \
		#
	hsh-initroot --no-lock "$workdir" \
		${hasher_priv_dir:+--hasher-priv-dir="$hasher_priv_dir"} \
		${quiet:+$quiet} \
		${verbose:+$verbose} \
		${cache_compress:+--cache-compress="$cache_compress"} \
		${cache_dir:+--cache-dir="$cache_dir"} \
		${no_cache:+--no-cache} \
		${no_contents_indices:+--no-contents-indices} \
		${repackage_source:+$repackage_source} \
		${exclude_docs:+--excludedocs} \
		${save_fakeroot:+--save-fakeroot} \
		${number:+--number=$number} \
		${nprocs:+--nprocs=$nprocs} \
		${install_langs:+--install-langs="$install_langs"} \
		${packager:+--packager="$packager"} \
		${init_list:+--pkg-init-list="$init_list"} \
		${build_list:+--pkg-build-list="$build_list"} \
		#
	[ -n "$f" ] || return 0
	hsh-rebuild --no-lock "$workdir" \
		${target:+--target="$target"} \
		${repo:+--repo="$repo"} \
		${repo_bin:+--repo-bin="$repo_bin"} \
		${repo_src:+--repo-src="$repo_src"} \
		${hasher_priv_dir:+--hasher-priv-dir="$hasher_priv_dir"} \
		${known_mountpoints:+--mountpoints="$known_mountpoints"} \
		${quiet:+$quiet} \
		${verbose:+$verbose} \
		${no_stuff:+--no-stuff} \
		${exclude_docs:+--excludedocs} \
		${save_fakeroot:+--save-fakeroot} \
		${no_sisyphus_check:+--no-sisyphus-check="$no_sisyphus_check"} \
		${no_sisyphus_check_in:+--no-sisyphus-check-in="$no_sisyphus_check_in"} \
		${no_sisyphus_check_out:+--no-sisyphus-check-out="$no_sisyphus_check_out"} \
		$build_srpm_only \
		${prog_rebuild:+--rebuild-prog="$prog_rebuild"} \
		${prog_query_req:+--query-req-prog="$prog_query_req"} \
		$query_repackage_option \
		${number:+--number=$number} \
		${rpmargs:+--rpmbuild-args="$rpmargs"} \
		-- "$f"
	if [ -z "$lazy_cleanup" -a -z "$initroot_only" ]; then
		[ ! -d chroot ] || hsh-rmchroot --no-lock "$workdir" \
		${hasher_priv_dir:+--hasher-priv-dir="$hasher_priv_dir"} \
		${quiet:+$quiet} \
		${verbose:+$verbose} \
		${number:+--number=$number} \
		#
		rm -rf aptbox
	fi
}

if [ -n "$printenv_only" ]; then
	set | sed -n 's/^hsh_cfg_var_\([^=]\+\)=$/\1/p' |
	while read i; do
		eval quote_shell_variable q "\$$i"
		[ -z "$q" ] ||
			printf '%s="%s"\n' "$i" "$q"
	done
	exit
fi

lock_workdir

if [ -n "$cleanup_only" ]; then
	cleanup_workdir
elif [ -n "$initroot_only" ]; then
	handle_package
else
	for f in "$@"; do
		handle_package "$f"
	done
fi
